package com.sinosoft.msf.base.supplier.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sinosoft.msf.base.supplier.dao.base.SCompanyRequestInfoMapper;
import com.sinosoft.msf.base.supplier.expection.BizException;
import com.sinosoft.msf.base.supplier.pojo.EnterpriseInfoPojo;
import com.sinosoft.msf.base.supplier.pojo.entity.SCompanyRequestInfo;
import com.sinosoft.msf.base.supplier.pojo.entity.SRequestLog;
import com.sinosoft.msf.base.supplier.pojo.tyc.*;
import com.sinosoft.msf.base.supplier.props.SupProps;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 天眼查相关接口
 */
@Service
public class TycService {
    private static final Logger log = LoggerFactory.getLogger(TycService.class);
    @Autowired
    AsyncSupService asyncSupService;
    @Autowired
    SCompanyRequestInfoMapper infoMapper;
    @Autowired
    StringRedisTemplate redisUtil;
    @Autowired
    private SupProps supProps = new SupProps();
    private List<String> normalState = Arrays.asList("正常", "开业", "在业", "存续");

    public EnterpriseInfoPojo queryAllInfo2(QueryVo queryVo) {
        SCompanyRequestInfo requestInfo = infoMapper.selectByPrimaryKey(queryVo.getQueryValue());
        EnterpriseInfoPojo enterpriseInfoPojo = JSONObject.parseObject(requestInfo.getResData(), EnterpriseInfoPojo.class);
        return enterpriseInfoPojo;
    }

    public EnterpriseInfoPojo queryAllInfo(QueryVo queryVo) {
        EnterpriseInfoPojo infoPojo = new EnterpriseInfoPojo();
        SearchVo.ItemsDTO itemsDTO = tycSearch(queryVo);
        BasicV3Info basicV3Info = tycBasicInfo(itemsDTO.getId());
        infoPojo.setComId(itemsDTO.getId());
        infoPojo.setName(basicV3Info.getName());
        infoPojo.setLegalPerson(basicV3Info.getLegalPersonName());
        infoPojo.setOperateStatus(basicV3Info.getRegStatus());
        infoPojo.setOperateStatusNormal(normalState.contains(basicV3Info.getRegStatus()));
        infoPojo.setSocialCreditCode(basicV3Info.getCreditCode());
        infoPojo.setRegisteredAddress(basicV3Info.getRegLocation());
        calDate(basicV3Info.getFromTime(), basicV3Info.getToTime(), infoPojo);
        infoPojo.setQueryData(DateUtil.now());
        BenefitVo benefitVo = tycBenefit(itemsDTO.getId());
        if (benefitVo != null) {
            if (CollUtil.isNotEmpty(benefitVo.getItems())) {
                // 提取全部收益人姓名用逗号分隔
                infoPojo.setBenefiter(benefitVo.getItems()
                        .stream()
                        .map(BenefitVo.ItemsDTO::getName)
                        .collect(Collectors.joining(",")));
//                BenefitVo.ItemsDTO dto = benefitVo.getItems().get(0);
//                infoPojo.setBenefiter(dto.getName());
            }
        }
        if (StrUtil.isEmpty(infoPojo.getBenefiter())) {
            infoPojo.setBenefiter("无");
        }
        List<String> licNotIn = new ArrayList<>();
        List<String> lic = new ArrayList<>();
        boolean licInDate = true;
        List<LicenseVo.ItemsDTO> itemsDTOS = tycLicense(itemsDTO.getId());
        for (LicenseVo.ItemsDTO dto : itemsDTOS) {
            boolean tempInDate = calTwoDate(dto.getFromdate(), dto.getTodate());
            String str = StrUtil.format("资格证名：{}；资格证号：{}；起止日期：[{}][{}]",
                    StrUtil.trim(StrUtil.emptyToDefault(dto.getLicencename(),"无")),
                    StrUtil.emptyToDefault(dto.getLicencenumber(),"无"),
                    StrUtil.emptyToDefault(dto.getFromdate(),"无"),
                    StrUtil.emptyToDefault(dto.getTodate(),"无"));
            if(!tempInDate){
                licNotIn.add(str);
            }
            lic.add(str);
            if (licInDate) {
                licInDate = tempInDate;
            }
        }
        infoPojo.setPermitInDate(licInDate);
        infoPojo.setPermitNotInDetail(String.join(";\n",licNotIn));
        infoPojo.setPermitDetail(String.join(";\n",lic));
        //基本信息填充完
        //开始填充异常信息：行政处罚、欠税、违法、存续状态异常、有失信被列入黑名单、经营异常、证照（含特许经营或行政审批）不在有效期内
        //行政处罚
        NumAndMsgVo punishmentInfo = tycPunishmentInfo(itemsDTO.getId());
        infoPojo.setAdminPunish(punishmentInfo.getNum());
        infoPojo.setAdminPunishDetail(punishmentInfo.getMsg());
        //查询欠税数量
        NumAndMsgVo tax = tycOwnTax(itemsDTO.getId());
        infoPojo.setOwnTaxCount(tax.getNum());
        infoPojo.setOwnTaxDetail(tax.getMsg());
        //查询严重违法--有失信被列入黑名单
        infoPojo.setIllegalInfoCount(tycIllegalinfo(itemsDTO.getId()));
        //经营异常数量
        infoPojo.setAbnormalCount(tycAbnormal(itemsDTO.getId()));
        //查询税收违法
        infoPojo.setTaxContraventionCount(tycTaxContravention(itemsDTO.getId()));

        infoPojo.setReqId(IdUtil.simpleUUID());
        SCompanyRequestInfo requestInfo = new SCompanyRequestInfo();
        requestInfo.setId(infoPojo.getReqId());
        requestInfo.setCreatedId("");
        requestInfo.setCreatedDate(DateUtil.date());
        requestInfo.setResData(JSON.toJSONString(infoPojo));
        requestInfo.setQueryValue(queryVo.getQueryValue());
        infoMapper.insert(requestInfo);
        return infoPojo;
    }

    private boolean calDate(String fromStr, String endStr, EnterpriseInfoPojo infoPojo) {
        boolean inDate = false;
        DateTime from = null;
        DateTime end = null;
        try {
            if (StrUtil.isNotEmpty(fromStr)) {
                from = DateUtil.beginOfDay(DateUtil.date(Long.parseLong(fromStr)));
                infoPojo.setLicenseStartDate(from.toDateStr());
            }
            if (StrUtil.isNotEmpty(endStr)) {
                end = DateUtil.beginOfDay(DateUtil.date(Long.parseLong(endStr)));
                infoPojo.setLicenseEndDate(end.toDateStr());
            }
            if(end == null){
                //天眼查反馈：结束日期是空表示是长期
                inDate = true;
            }else if(from != null){
                inDate = DateUtil.isIn(DateUtil.date(), from, end);
            }

        } catch (Exception ex) {
            log.error("日期转换错误，按照日期不在范围处理", ex);
        }
        infoPojo.setLicenseInDate(inDate);
        return inDate;
    }

    private boolean calTwoDate(String fromStr, String toStr) {
        if (StrUtil.isEmpty(fromStr) || StrUtil.isEmpty(toStr)) {
            return false;
        }
        boolean inDate = false;
        try {
            DateTime from = DateUtil.beginOfDay(DateUtil.parse(fromStr));
            DateTime end = DateUtil.endOfDay(DateUtil.parse(toStr));
            inDate = DateUtil.isIn(DateUtil.date(), from, end);
        } catch (Exception ex) {
            log.error("日期转换错误，按照日期不在范围处理", ex);
        }
        return inDate;
    }

    public Object cache(String bizType, String id) {
        return null;
//        String reKey = "sup:tyc:" + bizType + ":" + id;
//        Object o = redisUtil.opsForValue().get(reKey);
//        if (o != null) {
//            log.info("取缓存信息：{}",reKey);
//        }
//        return o;
    }
    public void setCache(String bizType, String id,Object v) {
        this.setCache(bizType,id,v,60*60*24);
    }
    public void setCache(String bizType, String id,Object v,long expire) {
        String reKey = "sup:tyc:" + bizType + ":" + id;
        redisUtil.opsForValue().set(reKey, JSONObject.toJSONString(v) , expire, TimeUnit.SECONDS);
    }
    /**
     * 经营异常数量
     *
     * @param id
     * @return
     */
    public Integer tycAbnormal(String id) {
        Integer abnormal = (Integer) cache("tycAbnormal", id);
        if (abnormal == null) {
            abnormal = tycAbnormalOrg(id);
            setCache("tycAbnormal", id,abnormal);
        }
        return abnormal;
    }
    public Integer tycAbnormalOrg(String id) {
        String inter = "/services/open/mr/abnormal/2.0";
        return queryCount(inter, id);
    }

    /**
     * 查询严重违法--有失信被列入黑名单
     *
     * @param id
     * @return
     */
    public Integer tycIllegalinfo(String id) {
        Integer abnormal = (Integer) cache("tycIllegalinfo", id);
        if (abnormal == null) {
            abnormal = tycIllegalinfoOrg(id);
            setCache("tycIllegalinfo", id,abnormal);
        }
        return abnormal;
    }
    public Integer tycIllegalinfoOrg(String id) {
        String inter = "/services/open/mr/illegalinfo/2.0";
        return queryCount(inter, id);
    }

    /**
     * 查询税收违法
     *
     * @param id
     * @return
     */
    public Integer tycTaxContravention(String id) {
        Integer abnormal = (Integer) cache("tycTaxContravention", id);
        if (abnormal == null) {
            abnormal = tycTaxContraventionOrg(id);
            setCache("tycTaxContravention", id,abnormal);
        }
        return abnormal;
    }
    public Integer tycTaxContraventionOrg(String id) {
        String inter = "/services/open/mr/taxContravention/2.0";
        return queryCount(inter, id);
    }

    /**
     * 查询欠税数量
     *
     * @param id
     * @return
     */
    public NumAndMsgVo tycOwnTax(String id) {
        NumAndMsgVo abnormal = (NumAndMsgVo) cache("tycOwnTax", id);
        if (abnormal == null) {
            abnormal = tycOwnTaxOrg(id);
            setCache("tycOwnTax", id,abnormal);
        }
        return abnormal;
    }
    public NumAndMsgVo tycOwnTaxOrg(String id) {
        NumAndMsgVo msgVo = new NumAndMsgVo();
        String inter = "/services/open/mr/ownTax/2.0";
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        ResVo resVo = excuteRequest(inter, param);
        if ("300000".equals(resVo.getErrorCode())) {
            msgVo.setNum(0);
            return msgVo;
        }
        if (StrUtil.isEmpty(resVo.getResult())) {
            msgVo.setNum(-1);
            msgVo.setMsg("欠税数据查询异常");
            return msgVo;
        }
        JSONObject jsonObject = JSON.parseObject(resVo.getResult());
        Integer total = jsonObject.getInteger("total");
        JSONArray items = jsonObject.getJSONArray("items");
        List<String> resList = new ArrayList<>();
        if (CollUtil.isNotEmpty(items)) {
            for (int i = 0; i < items.size(); i++) {
                JSONObject item = items.getJSONObject(i);
                String taxCategory = item.getString("taxCategory");
                String ownTaxAmount = item.getString("ownTaxAmount");
                resList.add("欠税类型：" + StrUtil.emptyToDefault(taxCategory,"无") + "金额：" + ownTaxAmount);
            }
        }
        msgVo.setMsg(String.join("；", resList));
        if (total != null) {
            msgVo.setNum(total);
        }
        return msgVo;
    }

    /**
     * 查询行政处罚数量
     *
     * @param id
     * @return
     */
    public NumAndMsgVo tycPunishmentInfo(String id) {
        NumAndMsgVo abnormal = (NumAndMsgVo) cache("tycPunishmentInfo", id);
        if (abnormal == null) {
            abnormal = tycPunishmentInfoOrg(id);
            setCache("tycPunishmentInfo", id,abnormal);
        }
        return abnormal;
    }
    public NumAndMsgVo tycPunishmentInfoOrg(String id) {
        NumAndMsgVo msgVo = new NumAndMsgVo();
        String inter = "/services/open/mr/punishmentInfo/3.0";
        Map<String, Object> param = new HashMap<>();
        param.put("keyword", id);
        ResVo resVo = excuteRequest(inter, param);
        if ("300000".equals(resVo.getErrorCode())) {
            msgVo.setNum(0);
            return msgVo;
        }
        if (StrUtil.isEmpty(resVo.getResult())) {
            msgVo.setNum(-1);
            msgVo.setMsg("欠税数据查询异常");
            return msgVo;
        }
        JSONObject jsonObject = JSON.parseObject(resVo.getResult());
        Integer total = jsonObject.getInteger("total");
        JSONArray items = jsonObject.getJSONArray("items");
        List<String> resList = new ArrayList<>();
        if (CollUtil.isNotEmpty(items)) {
            for (int i = 0; i < items.size(); i++) {
                JSONObject item = items.getJSONObject(i);
                String source = item.getString("source");
                String decisionDate = item.getString("decisionDate");
                resList.add("处罚部门：" + StrUtil.emptyToDefault(source,"无") + "时间：" + decisionDate);
            }
        }
        msgVo.setMsg(String.join("；", resList));
        if (total != null) {
            msgVo.setNum(total);
        }
        return msgVo;
    }



    /**
     * 查询执业证
     *
     * @param id
     * @return
     */
    public List<LicenseVo.ItemsDTO> tycLicense(String id) {
        List<LicenseVo.ItemsDTO> abnormal = (List<LicenseVo.ItemsDTO>) cache("tycLicense", id);
        if (abnormal == null) {
            abnormal = tycLicenseOrg(id);
            setCache("tycLicense", id,abnormal);
        }
        return abnormal;
    }
    public List<LicenseVo.ItemsDTO> tycLicenseOrg(String id) {
        String inter = "/services/open/m/getLicense/2.0";
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        ResVo resVo = excuteRequest(inter, param);
        LicenseVo licenseVo = transVo(resVo.getResult(), LicenseVo.class);
        List<LicenseVo.ItemsDTO> items = new ArrayList<>();
        if (licenseVo == null) {
            return items;
        }
        items = licenseVo.getItems();
        return items;
    }

    /**
     * 查询最终受益人
     *
     * @param id
     * @return
     */
    public BenefitVo tycBenefit(String id) {
        BenefitVo abnormal = (BenefitVo) cache("tycBenefit", id);
        if (abnormal == null) {
            abnormal = tycBenefitOrg(id);
            setCache("tycBenefit", id,abnormal);
        }
        return abnormal;
    }
    public BenefitVo tycBenefitOrg(String id) {
        String inter = "/services/open/ic/humanholding/2.0";
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        ResVo resVo = excuteRequest(inter, param);
        BenefitVo benefitVo = transVo(resVo.getResult(), BenefitVo.class);
        return benefitVo;
    }

    /**
     * 查询基本信息
     *
     * @param id
     * @return
     */
    public BasicV3Info tycBasicInfo(String id) {
        BasicV3Info abnormal = (BasicV3Info) cache("tycBasicInfo", id);
        if (abnormal == null) {
            abnormal = tycBasicInfoOrg(id);
            setCache("tycBasicInfo", id,abnormal);
        }
        return abnormal;
    }
    public BasicV3Info tycBasicInfoOrg(String id) {
        String inter = "/services/open/ic/baseinfoV3/2.0";
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        ResVo resVo = excuteRequest(inter, param);
        BasicV3Info basicV3Info = transVo(resVo.getResult(), BasicV3Info.class);
        if (basicV3Info == null) {
            throw new BizException("未查询到企业信息");
        }
        return basicV3Info;
    }

    /**
     * 股权穿透图
     * @param id 公司Id
     * @return
     */
    public List<InvestVo> investtree(String id) {
        return investtree(id, "pro");
    }
    public List<InvestVo> investtree(String id,String source) {
        List<InvestVo> abnormal = null;
        if ("pro".equalsIgnoreCase(source)) {
            //项目的查询--使用1天缓存
            abnormal = (List<InvestVo>) cache("investtree", id);
        }else{
            //供应商的查询-使用7天缓存
            abnormal = (List<InvestVo>) cache("investtree-7", id);
        }

        if (abnormal == null) {
            abnormal = investtreeOrg(id);
            setCache("investtree", id,abnormal);
            setCache("investtree-7", id,abnormal,60*60*24*7);
        }
        return abnormal;
    }
    public List<InvestVo> investtreeOrg(String id) {
        String inter = "/services/v3/open/investtree";
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("flag", "3");
        ResVo resVo = excuteRequest(inter, param);
        String result = resVo.getResult();
        List<InvesttreeVo> investtreeVo = JSON.parseArray(result, InvesttreeVo.class);
        List<InvestVo> res = new ArrayList<>();
        fetchChild(investtreeVo, res);
        return res;
    }

    public void fetchChild(List<InvesttreeVo> treeVos, List<InvestVo> res) {
        if (CollUtil.isNotEmpty(treeVos)) {
            for (InvesttreeVo treeVo : treeVos) {
                InvestVo vo = new InvestVo();
                BeanUtil.copyProperties(treeVo, vo);
                res.add(vo);
                if (CollUtil.isNotEmpty(treeVo.getChildren())) {
                    fetchChild(treeVo.getChildren(), res);
                }
            }
        }
    }

    /**
     * 查询匹配的企业，过滤一个完全匹配的
     *
     * @param queryVo
     * @return
     */
    public SearchVo.ItemsDTO tycSearch(QueryVo queryVo) {
        String inter = "/services/open/search/2.0";
        Map<String, Object> param = new HashMap<>();
        param.put("word", queryVo.getQueryValue());
        ResVo resVo = excuteRequest(inter, param);
        SearchVo searchVo = transVo(resVo.getResult(), SearchVo.class);
        if (searchVo == null) {
            throw new BizException("未查询到企业信息");
        }
        SearchVo.ItemsDTO itemsDTO = searchVo.getItems().stream().filter(item -> {
            if (queryVo.getQueryValue().equals(item.getName()) ||
                    queryVo.getQueryValue().equals(item.getCreditCode()) ||
                    queryVo.getQueryValue().equals(item.getRegNumber())
            ) {
                return true;
            } else {
                return false;
            }
        }).findFirst().orElseThrow(() -> new BizException("未查询到企业信息"));
        return itemsDTO;
    }

    public <T> T transVo(String txt, Class<T> clazz) {
        if (StrUtil.isEmpty(txt)) {
            return null;
        }
        return JSON.parseObject(txt, clazz);
    }


    public Integer queryCount(String inter, String id) {
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        ResVo resVo = excuteRequest(inter, param);
        if ("300000".equals(resVo.getErrorCode())) {
            return 0;
        }
        if (StrUtil.isEmpty(resVo.getResult())) {
            return -1;
        }
        JSONObject jsonObject = JSON.parseObject(resVo.getResult());
        Integer total = jsonObject.getInteger("total");
        if (total == null) {
            return -1;
        }
        return total;
    }
    private static String paramsConvertUrl(Map<String, Object> param) {
        if(param==null){
            return "";
        }
        return param.entrySet().stream()
                .map(e -> {
                    try {
                        String encodedValue = URLEncoder.encode(String.valueOf(e.getValue()), StandardCharsets.UTF_8.toString());
                        return String.format("%s=%s", e.getKey(), encodedValue);
                    } catch (UnsupportedEncodingException uee) {
                        throw new RuntimeException("UTF-8 encoding not supported", uee);
                    }
                })
                .collect(Collectors.joining("&"));
    }
    public ResVo excuteRequest(String interPath, Map<String, Object> param) {
        TimeInterval timer = DateUtil.timer();
        ResVo resVo = new ResVo();
        SRequestLog requestLog = new SRequestLog();
        try {
            String url = supProps.getTycHost() + interPath;
            requestLog.setReqUrl(url);
            requestLog.setReqData(JSON.toJSONString(param));
            String urlParam = paramsConvertUrl(param);

            OkHttpClient client = new OkHttpClient().newBuilder()
                    .connectTimeout(180, TimeUnit.SECONDS)
                    .readTimeout(180, TimeUnit.SECONDS)
                    .writeTimeout(180, TimeUnit.SECONDS)
                    .build();

            String dataUrl = url + "?" + urlParam;
            log.info("Okhttp请求的路径为：{}",dataUrl);
            Request request = new Request.Builder()
                    .url(dataUrl)
                    .addHeader("Authorization", supProps.getTycToken())
                    .get()
                    .build();
            int statusCode = 0;
            try {
                Response response = client.newCall(request).execute();
                statusCode = response.code();
                ResponseBody responseBody = response.body();
                if (responseBody != null) {
                    String body = responseBody.string();
                    log.info("接口路径：{},返回报文：{}", interPath, body);
                    if (StrUtil.isNotEmpty(body)) {
                        JSONObject resObj = JSON.parseObject(body);
                        String errorCode = resObj.getString("error_code");
                        resVo.setErrorCode(errorCode);
                        resVo.setResult(resObj.getString("result"));
                        requestLog.setReqCode(errorCode);
                        requestLog.setResData(body);
                    }
                }
            } catch (Exception e) {
                log.error("请求发生异常，",e);
            }
            long interval = timer.interval();
            requestLog.setResHttpState(statusCode + "");
            requestLog.setResCost(interval + "");
        } finally {
//            asyncSupService.saveReqHis(requestLog, "");
        }

        return resVo;
    }

}
